﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.ServiceModel.Syndication;
using System.Xml;
using System.Xml.Linq;
using Microsoft.SharePoint.UserCode;

namespace CKS.Sandbox.DailyDilbert.Proxy
{
    /// <summary>
    /// The Daily Dilbert Proxy class. Retrieves the feed data.
    /// </summary>
    public class DailyDilbertProxyOperation : SPProxyOperation
    {
        /// <summary>
        /// Gets the feed data
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public override object Execute(SPProxyOperationArgs args)
        {
            DailyDilbertProxyOperationArgs feedArgs = null;
            DailyDilbertFeedData data= null;

            if (args != null)
            {
                if (args is DailyDilbertProxyOperationArgs)
                {
                    feedArgs = args as DailyDilbertProxyOperationArgs;
                    string feedSource = feedArgs.FeedUrl;
                    if (string.IsNullOrEmpty(feedSource))
                    {
                        data = GetDataWithErrorMessage("FeedUrl property of parameter \"Args\" is null.");
                    }
                    else
                    {
                        XmlReader reader = null;
                        string exceptionMessage = "Exception while reading the feed";
                        try
                        {
                            reader = XmlReader.Create(feedSource);
                        }
                        catch (SecurityException ex)
                        {
                            data = GetDataWithErrorMessage(exceptionMessage, ex);
                        }
                        catch (FileNotFoundException ex)
                        {
                            data = GetDataWithErrorMessage(exceptionMessage, ex);
                        }
                        catch (UriFormatException ex)
                        {
                            data = GetDataWithErrorMessage(exceptionMessage, ex);
                        }

                        if (reader != null)
                        {
                            try
                            {
                                data = new DailyDilbertFeedData();
                                data.IsError = false;
                                data.Items = new List<DailyDilbertFeedItemData>();
                                DailyDilbertFeedItemData itemData = null;
                                SyndicationFeed feed = SyndicationFeed.Load(reader);
                                data.LastUpdatedDate = feed.LastUpdatedTime;
                                data.Title = feed.Title.Text;

                                foreach (SyndicationItem item in feed.Items)
                                {
                                    itemData = new DailyDilbertFeedItemData();
                                    itemData.Title = item.Title.Text;
                                    itemData.PublishDate = item.PublishDate;
                                    itemData.ImageSource = GetImageSourceFromSummary(item.Summary.Text); ;
                                    data.Items.Add(itemData);
                                }
                            }
                            catch (Exception ex)
                            {
                                data = GetDataWithErrorMessage(exceptionMessage, ex);
                            }
                        }
                    }
                }
                else
                {
                    data = GetDataWithErrorMessage("Parameter \"Args\" is not of expected type.");
                }
            }
            else
            {
                data = GetDataWithErrorMessage("Parameter \"Args\" is null");
            }

            return data;
        }

        /// <summary>
        /// Retrieves the image url from the summary element of the feed item.
        /// </summary>
        /// <param name="summary">The summary text</param>
        /// <returns>Url of the image</returns>
        private static string GetImageSourceFromSummary(string summary)
        {
            string xml = summary;
            string imgSrc = string.Empty;
            if(!string.IsNullOrEmpty(xml))
            {
                try
                {
                    xml = string.Concat("<root>", xml, "</root>");
                    XElement element= XElement.Parse(xml);
                    imgSrc = element.Element("img").Attribute("src").Value;
                }
                catch 
                {
                }
            }

            return imgSrc;
        }

        /// <summary>
        /// Returns a DailyDilbertFeedData instance with error message set.
        /// </summary>
        /// <param name="message">The contextual error message.</param>
        /// <returns>DailyDilbertFeedData with error message set</returns>
        private static DailyDilbertFeedData GetDataWithErrorMessage(string message)
        {
            DailyDilbertFeedData data = new DailyDilbertFeedData();
            data.IsError = true;
            data.ErrorMessage = message;
            return data;
        }

        /// <summary>
        /// Returns a DailyDilbertFeedData instance with error message set to the exception message.
        /// </summary>
        /// <param name="message">The contextual error message.</param>
        /// <param name="ex">The exception.</param>
        /// <returns>DailyDilbertFeedData with error message set</returns>
        private static DailyDilbertFeedData GetDataWithErrorMessage(string message, Exception ex)
        {
            return GetDataWithErrorMessage(message + ". " + ex.GetType() + ". " + ex.Message);
        }
    }
}
